from __future__ import annotations

from dataclasses import dataclass
from math import radians, tan, sin, cos
from typing import List


@dataclass
class BishopSlice:
    width_m: float
    height_m: float
    unit_weight_kN_m3: float
    cohesion_kPa: float
    friction_deg: float
    base_inclination_deg: float
    pore_pressure_kPa: float = 0.0


@dataclass
class BishopResult:
    factor_of_safety: float
    iterations: int
    converged: bool
    note: str


def bishop_simplified(slices: List[BishopSlice], tol: float = 1e-4, max_iter: int = 200) -> BishopResult:
    """圆弧滑动Bishop简化法（不考虑外力矩），迭代求Fs。

    公式：Fs = Σ[(c' b + (W - u b) tanφ')·m]/Σ(W sinα)，其中 m = 1 / (1 + (tanφ' tanα)/Fs)
    参考：Bishop (1955) Simplified Method of Slices。
    """

    def compute_F(F_guess: float) -> float:
        numerator = 0.0
        denominator = 0.0
        for s in slices:
            b = s.width_m
            W = s.width_m * s.height_m * s.unit_weight_kN_m3
            alpha = radians(s.base_inclination_deg)
            phi = radians(s.friction_deg)
            u = s.pore_pressure_kPa / 1000.0  # kN/m2
            m = 1.0 / (1.0 + (tan(phi) * tan(alpha)) / max(1e-9, F_guess))
            numerator += (s.cohesion_kPa / 1000.0 * b + (W - u * b) * tan(phi)) * m
            denominator += W * sin(alpha)
        return numerator / max(1e-9, denominator)

    F = 1.0
    converged = False
    for it in range(1, max_iter + 1):
        F_new = compute_F(F)
        if abs(F_new - F) < tol:
            F = F_new
            converged = True
            return BishopResult(factor_of_safety=F, iterations=it, converged=converged, note="Bishop简化收敛")
        F = 0.5 * (F + F_new)
    return BishopResult(factor_of_safety=F, iterations=max_iter, converged=converged, note="未收敛，检查分块与参数")


